import chalk from 'chalk';
import readline from 'readline';
import stringWidth from 'string-width';
import process from "process";
import {DateUtil} from "./DateUtil.js";
import ansiRegex from "ansi-regex";
import {StrUtil} from "./StrUtil.js";

export class InfoConsoleTable {

    constructor(type) {
        this.data = [];
        this.showHeader = false;
        // 状态颜色
        this.TABLE_STATUS = {
            success: chalk.green('●成功'),
            normal: chalk.green('●正常'),
            error: chalk.red('●异常'),
            warn: chalk.yellow('●警告'),
            wait: chalk.blue('●等待'),
            canceled: chalk.white('●取消'),
            un: chalk.white('●无'),
            running: chalk.cyan('●运行')
        };
        this.type = type;
        this.headerOffset = 3;

        // 类型颜色
        this.TYPE_COLOR = {
            support: chalk.yellow('依赖'),
            app: chalk.cyan('应用'),
            plugin: chalk.cyan('插件'),
            jz: chalk.magenta('基座')
        };

        // 列宽配置（Info 专用）
        this.COL_WIDTHS = {
            num: 3,
            type: 7,
            name: 28,
            buildStatus: 82,
            sonarStatus: 15,
            runStatus: 40,
            time: 16,
            desc: 100
        };
    }

    pad(str, width) {
        const cleanStr = str.replace(ansiRegex(), '');
        const visibleLength = stringWidth(cleanStr);

        if (visibleLength > width) {
            let truncated = '';
            let len = 0;
            for (const char of cleanStr) {
                const charWidth = stringWidth(char);
                if (len + charWidth > width - 1) break;
                truncated += char;
                len += charWidth;
            }
            return truncated + '…';
        }
        return str + ' '.repeat(width - visibleLength);
    }

    printBorder() {
        const totalWidth = Object.values(this.COL_WIDTHS).reduce((a, b) => a + b, 0);
        console.log('-'.repeat(totalWidth));
    }

    printHeader() {
        if (this.showHeader) {
            return;
        }
        this.showHeader = true;
        this.printBorder();
        let header =
            this.pad(' ', this.COL_WIDTHS.num) +
            this.pad('类型', this.COL_WIDTHS.type) +
            this.pad('服务', this.COL_WIDTHS.name) +
            this.pad('构建', this.COL_WIDTHS.buildStatus);
        switch (this.type) {
            case '依赖发布单':
                break;
            case '发布单':
                header = header +
                    this.pad('扫描', this.COL_WIDTHS.sonarStatus) +
                    this.pad('启动', this.COL_WIDTHS.runStatus);
                break;
            case '普通发布':
                header = header +
                    this.pad('扫描', this.COL_WIDTHS.sonarStatus) +
                    this.pad('启动', this.COL_WIDTHS.runStatus);
                break;
        }
        header = header +
            this.pad('更新时间', this.COL_WIDTHS.time) +
            this.pad('描述', this.COL_WIDTHS.desc);
        console.log(chalk.bold(header));
    }

    buildLine(row, index) {
        let line =
            this.pad(String(index + 1), this.COL_WIDTHS.num) +
            this.pad(this.TYPE_COLOR[row.type] || row.type, this.COL_WIDTHS.type) +
            this.pad(StrUtil.hyperlink(row.name, row.opsUrl), this.COL_WIDTHS.name) +
            this.pad(this.TABLE_STATUS[row.buildStatus] + (row.buildDesc ? ` ${row.buildDesc}` : ''), this.COL_WIDTHS.buildStatus);

        switch (this.type) {
            case '依赖发布单':
                break;
            case '发布单':
                line = line +
                    this.pad(this.TABLE_STATUS[row.sonarStatus] + (row.sonarDesc ? ` ${row.sonarDesc}` : ''), this.COL_WIDTHS.sonarStatus) +
                    this.pad(this.TABLE_STATUS[row.runStatus] + (row.runDesc ? ` ${row.runDesc}` : ''), this.COL_WIDTHS.runStatus);
                break;
            case '普通发布':
                line = line +
                    this.pad(this.TABLE_STATUS[row.sonarStatus] + (row.sonarDesc ? ` ${row.sonarDesc}` : ''), this.COL_WIDTHS.sonarStatus);
                const combinedDescParts = [];
                if (row.deployDesc) {
                    combinedDescParts.push(`部署${row.deployDesc}`);
                }
                if (row.runDesc) {
                    combinedDescParts.push(row.runDesc);
                }
                const statusKey = this.TABLE_STATUS[row.runStatus] ? row.runStatus : 'wait';
                const statusLabel = this.TABLE_STATUS[statusKey] || '';
                const combinedText = `${statusLabel}${combinedDescParts.length ? ` ${combinedDescParts.join(' | ')}` : ''}`;
                line = line + this.pad(combinedText, this.COL_WIDTHS.runStatus);
                break;
        }
        return line +
            this.pad(row.time, this.COL_WIDTHS.time) +
            this.pad((row.desc || ''), this.COL_WIDTHS.desc);
    }

    moveCursorToBottom() {
        if (!process.stdout?.isTTY) {
            return;
        }
        readline.cursorTo(process.stdout, 0);
    }

    printRow(row, index) {
        const line = this.buildLine(row, index);
        if (!process.stdout?.isTTY) {
            console.log(line);
            return;
        }
        const rowsToBottom = this.data.length - index;
        readline.moveCursor(process.stdout, 0, -rowsToBottom);
        readline.clearLine(process.stdout, 0);
        process.stdout.write(line + '\n');
        readline.moveCursor(process.stdout, 0, rowsToBottom - 1);
    }

    addRow(rowObj) {
        const index = this.data.length;
        this.data.push(rowObj);
        if (!process.stdout?.isTTY) {
            console.log(this.buildLine(rowObj, index));
            return;
        }
        const line = this.buildLine(rowObj, index);
        process.stdout.write(line + '\n');
    }

    getRow(appName) {
        const index = this.data.findIndex(r => r.name === appName);
        return this.data[index];
    }

    updateRow(newRow) {
        const index = this.data.findIndex(r => r.name === newRow.name);
        if (index === -1) {
            console.error(`未找到服务: ${newRow.name}`);
            return;
        }
        this.data[index] = {...this.data[index], ...newRow};
        this.data[index].time = DateUtil.nowTime();
        this.printRow(this.data[index], index);
    }
}
